Repository navigation
[FlyDSL] Add gfx950 FHMoE tuner in fhmoe_tune.py - #5751
a-canadasruiz wants to merge 5 commits into
Conversation
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
PR title tags & labels: |
25a6fb6 to
1dfc0b3
Compare
c12acdc to
bdac6e9
Compare
6d19303 to
f1321b1
Compare
685936f to
3e81963
Compare
eb191ba to
1febc43
Compare
1febc43 to
d766370
Compare
NOT READY FOR HUMAN REVIEWPR Self-ReviewRevision Author self-review accepted. Readiness report: Author answers
Show the author's self-review answersBehavior and intentValidation and unverified scopePR-specific questionChanged op testsPR state
Copilot findings
Code and op-test hygiene
Required CI
Shadow mode reports what would block but keeps the status successful. Set |
Add FhmoeTuner in its own module, fhmoe_tune.py, for the DeepSeek-V4 INTERLEAVE FHMoE path on gfx950 (routed MXFP4 experts plus one FP8 shared expert). It subclasses TunerCommon and imports the few helpers it needs from gemm_moe_tune.py, which is left unchanged. - untuned_fhmoe.csv lists the serving buckets, 1 to 2048 tokens. - Each task times one FlyDSL stage1 x stage2 pair through fused_moe, fused and non-fused stage1 quant, with --warmup/--iters. - Weights are quantized on the CPU (DSv4 MXFP4 quant peaks at several GiB), so the worker only times fused_moe on the GPU. - Candidates are checked against a torch reference before timing. - Rows are published under the padded token and only the tuner's own rows of tuned_fhmoe.csv are rewritten. - Tokens that are not serving buckets are rejected, and rows pinned to another gfx/cu_num are skipped.
Cover token buckets, kernel pairs, post_process, the CSV rewrite and the gfx/cu_num guard without a GPU, and run them in the level 0+1 job.
- test_csv_validation: no duplicate shapes, and catalogue tokens are serving buckets. - test_run_config: fhmoe_dsv4 family. - test_tune_pipeline: small mp=1 tune on gfx950. - test_fhmoe_replay: replay the tuner output through the public fused_moe in a fresh process (manual, gfx950).
Add an fhmoe job and skip it on anything but gfx950, so Operators Tuning on gfx942 does not fail.
… the kernel MXFP8 activations quantize between and inside the stages. Compare each candidate with the closest of two torch references that quantize the same way (bf16-rounded and fp32), and have run_config retry with the fp32 one when the first misses. Rows with fp4 activations still use the unquantized reference; warn when a row is checked that way.
d766370 to
8b80abe
Compare
Summary
Add a tuner for the DeepSeek-V4 FHMoE rows in
aiter/configs/tuned_fhmoe.csvon gfx950:csrc/ck_gemm_moe_2stages_codegen/fhmoe_tune.py.Those rows already serve through
fused_moe, but nothing in the repo could produce or re-check them.Motivation
DSv4 FHMoE runs routed MXFP4 experts plus one FP8 shared expert in a single launch (E=385, topk 7, shared expert 384,
GateMode.INTERLEAVE). There was no tuner for its rows in the repo: no way to retune a shape, add a new one, or check with--run_configthat the shipped rows still match torch.Since #6050, the same CSV also holds the HY4 rows, tuned by
op_tests/tuners/tune_fhmoe.py. This tuner only touches rows with MXFP4 weights (DSv4) and skips the FP8-weight HY4 rows. The HY4 tuner can't cover DSv4 as it is: its shape, FP8 weights, kernel list and reference are fixed in the script, and it only retunes rows that already exist, on one GPU. This tuner reads the shape fromuntuned_fhmoe.csv, can add new shapes, runs on several GPUs throughmp_tunerand has--run_config. One FHMoE tuner for both models would be a follow-up.Changes
The commits follow this list.
FhmoeTunerin its own module,fhmoe_tune.py, next togemm_moe_tune.py, plus the catalogueuntuned_fhmoe.csv(12 serving buckets, 1 to 2048 tokens).TunerCommonand imports a few helpers fromgemm_moe_tune.py(weight quant, the torch stage references,cosine_diff_compare).gemm_moe_tune.pyis not changed.block_m. Stage 1 comes in fused and non-fused quant (_fp8suffix). That is about 5632 pairs per token. The kernel list follows the row's activation and weight dtypes, as inFmoeTuner._fused_moe_implwith a one-row temp CSV. The publicfused_moe()cannot take that file, because DSv4 serving needs every padded-M tier in the config.get_padded_M(token).gfx/cu_numare skipped.fused_moe.FhmoeTuner(test_fhmoe_dsv4_tuner.py), run in the level 0+1 job.fhmoe_dsv4: CSV validation,--run_config, a small tune pipeline, and a manual replay test.op_tune.sh: a newfhmoejob, skipped on anything but gfx950. It does not pass--all, so it is a no-op until a new shape is added to the catalogue.--run_configtries the fp32 variant only when the first one misses. Serving code (fused_moe,aiter/fhmoe.py) is not changed. The shippedtuned_fhmoe.csvis not changed.Testing
PR Self-Review
Reviewed revision
8b80abe
Behavior and intent
Adds a tuner path only: a new script,
fhmoe_tune.py. Before this PR the DSv4 rows oftuned_fhmoe.csvcould not be retuned or checked with--run_config.gemm_moe_tune.pyis not changed. Serving and the shipped CSV are unchanged.Validation and unverified scope
On MI355X (gfx950), at this revision, all passed:
test_fhmoe_dsv4_tuner,test_csv_validation(CPU, 51 tests)test_fhmoe_replay(3 tests)test_tune_pipeline ... test_fhmoe_dsv4_mp1test_run_config ... test_fhmoe_dsv4: 12 shipped DSv4 rows, no ERROR or MISMATCHNot verified:
tuning-tests.yamlruns on schedule orworkflow_dispatchonly, so this PR's CI does not run it.PR-specific question
No new permissions, secrets or triggers.
op_tune.shgets one job entry and a gfx950 check.tuning-tests.yamladds one module to the level 0+1 command. Both workflows run only onscheduleorworkflow_dispatch, so fork PR code or text cannot reach them.Changed op tests
test_fhmoe_dsv4_tuner.py: CPU tests forFhmoeTuner, including that a rewrite keeps the HY4 rows. Nothing else covers it.test_fhmoe_replay.py: replays the tuner output through the publicfused_moe. Manual, gfx950.test_csv_validation.py: no duplicate shapes, catalogue tokens are serving buckets.test_run_config.py: adds thefhmoe_dsv4family.test_tune_pipeline.py: small--mp 1tune forfhmoe_dsv4.README.md: documents the new tests and family.test_fhmoe.py:__main__now runspytest.main. Before, it exited 0 without running any test.